//
// Created by afly on 20-12-28.
// Mail: a_fly0505@163.com
// QQ: 785230837 WX: afly003
// Company: juefx
//

/**
 * @file thread_pool.cpp
 * @author yunfei.zhao (yunfei.zhao@i-soft.com.cn)
 * @brief 
 * @version 0.1
 * @date 2021-09-17
 * @copyright Copyright (c) 2021
*/

/**
 * @copyright Copyright (c) 2021
 * @file thread_pool.cpp
 * @author yunfei.zhao (yunfei.zhao@i-soft.com.cn)
 * @brief 
 * @version 0.1
 * @date 2021-09-17
 * 
 * 
*/

#include <chrono>
#include <iostream>

#include "thread_pool.h"
#include "thread_qsm.h"

using namespace std;

namespace qsm {

ThreadPool::ThreadPool(const char *name) : m_IsRun(false), m_IsPause(false) { m_ThreadPoolName = name; }

ThreadPool::~ThreadPool() {
}

/**
 * @brief 
 * 
 * @param threadNum 
 * @return int 
*/
int ThreadPool::Start(int threadNum) {
    m_ThreadNum = threadNum;
    if (m_ThreadNum <= 0) {
        m_ThreadNum = std::thread::hardware_concurrency();
    }
    m_Workers.clear();
    m_IsRun = true;
    for (int i = 0; i < m_ThreadNum; i++) {
        Thread *t = new Thread(std::bind(&ThreadPool::task_func, this));
        // t->SetSetafftinityNp();
        // t->native_handle();
        // t->get_id();
        m_Workers.push_back(t);
    }
    return 0;
}

bool ThreadPool::IsStart() const { return m_IsRun; }

int ThreadPool::GetThreadNum() const { return m_ThreadNum; }

int ThreadPool::GetTaskNums() {
    std::unique_lock<std::mutex> lock(m_QueueMutex);
    return m_Tasks.size();
}

void ThreadPool::SetMaxTaskNums(int maxTaskNum) {
    if (maxTaskNum <= 0) {
        return;
    }
    m_MaxTaskNum = maxTaskNum;
    return;
}

void ThreadPool::task_func() {
    std::this_thread::get_id();
    while (m_IsRun) {
        chrono::steady_clock::time_point nextPointTime = chrono::steady_clock::now();
        if (m_IsPause) {
            std::unique_lock<std::mutex> lock(m_PauseMutex);
            m_PauseCondition.wait(lock);
        }

        ProcFuncNode_t pTaskNode;
        {
            std::unique_lock<std::mutex> lock(m_QueueMutex);

            while (m_Tasks.size() <= 0) {
                m_Condition.wait(lock);
                if (!m_IsRun) {
                    return;
                }
            }
            pTaskNode = m_Tasks.front();
            m_Tasks.pop_front();
        }

        if (m_IsPause) {
            std::unique_lock<std::mutex> lock(m_PauseMutex);
            m_PauseCondition.wait(lock);
        }

        if (!pTaskNode) {
            continue;
        }

        std::chrono::steady_clock::time_point getTaskTime = std::chrono::steady_clock::now();
        if (0 != pTaskNode(pthread_self())) {
            m_FaileNum++;
        }
        m_TotalNum++;
        chrono::steady_clock::time_point endTime = chrono::steady_clock::now();
        chrono::steady_clock::duration pool_one_task_time = endTime - nextPointTime;
        chrono::steady_clock::duration task_exec_time = endTime - getTaskTime;
        cout << m_ThreadPoolName << " thread pool, tid=" << this_thread::get_id() << " on CPU " << sched_getcpu()
             << " the time it takes to perform one task(competition) is " << double(pool_one_task_time.count()) / 1000
             << " us";
        cout << m_ThreadPoolName << " thread pool, tid=" << this_thread::get_id()
             << " the time it takes to perform one task is " << double(task_exec_time.count()) / 1000 << " us";
    }
    return;
}

int ThreadPool::Stop() {
    if (!m_IsRun) {
        return 0;
    }

    m_IsRun.store(false);
    m_Condition.notify_all();
    for (int i = 0; i < m_ThreadNum; i++) {
        m_Workers[i]->join();
    }
    m_Workers.clear();
    std::cout << __FUNCTION__ << std::endl;
    return 0;
}

int ThreadPool::Pause() {
    m_IsPause = true;
    return 0;
}
/**
/**@brief 
/**
/**@return int 
*/
int ThreadPool::Continue() {
    m_IsPause = false;
    m_PauseCondition.notify_all();
    return 0;
}

/**
 * @brief 
 * 
 * @param tasknode 
 * @return int 
*/
int ThreadPool::Commit(ProcFuncNode_t tasknode) {
    if (!tasknode) {
        return 1;  // todo
    }

    if (!m_IsRun) {
        cout << "thread pool isn't run: " << m_ThreadPoolName << std::endl;
    }

    std::unique_lock<std::mutex> lock(m_QueueMutex);
    if (m_MaxTaskNum > 0 && (m_Tasks.size() > m_MaxTaskNum)) {
        std::list<ProcFuncNode_t>::iterator iter;
        cout << "thread name=" << m_ThreadPoolName << " TaskNum=" << m_Tasks.size() << " limit num=" << m_MaxTaskNum
             << " delete some frame regularly";
        int i = 0;
        for (iter = m_Tasks.begin(); iter != m_Tasks.end();) {
            if (0 == i % 3) {
                iter = m_Tasks.erase(iter);
                cout << "thread name=" << m_ThreadPoolName << "delete one";
            } else {
                iter++;
            }
            i++;
        }
    }

    m_Tasks.push_back(tasknode);
    std::cout << "thread pool name=" << m_ThreadPoolName << " queue size=" << m_Tasks.size() << endl;
    m_Condition.notify_one();
    return 0;
}
}  // namespace qsm
